﻿using System;
using System.Threading;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;

using PickGold.Handler;
using PickGold.Arguments;
using PickGold.Exceptions;

namespace PickGold.Callers
{
	/// <summary>
	/// Repeat Runner
	/// </summary>
	public class CRepeatRunner : IDisposable
	{
		private static CRepeatRunner _Value;
		private static AsyncCallback _InvokeAsyncCallback = null;
		private static Dictionary<Thread, CRepeatRunner> _RepeatRunnerDictionary = new Dictionary<Thread, CRepeatRunner>();
		private int _Delay;// volatile
		private int _RanTimes;// volatile
		private int _ErrorTimes;// volatile
		private int _ThreadState;// volatile
		private bool _IsDisposed;
		private object _Tag;// volatile
		private Thread _Thread;// volatile // 为空则线程结束
		private IDelegate _Handler;// volatile
		private ManualResetEvent _DelayWait;// volatile // 为空则销毁

		/// <summary>
		/// 线程错误
		/// </summary>
		public event HErrorEventHandler Error;

		/// <summary>
		/// 默认实例
		/// </summary>
		public static CRepeatRunner Value
		{
			get
			{
				if (CRepeatRunner._Value == null)
					CRepeatRunner._Value = new CRepeatRunner();
				return CRepeatRunner._Value;
			}
		}

		/// <summary>
		/// 当前线程的重复运行对象。如果不存在则为空。
		/// </summary>
		public static CRepeatRunner Current
		{
			get
			{
				return CRepeatRunner.GetRunner(Thread.CurrentThread);
			}
		}

		/// <summary>
		/// 构造一反复运行对象
		/// </summary>
		public CRepeatRunner() : this(null) { }
		/// <summary>
		/// 构造一反复运行对象
		/// </summary>
		/// <param name="handler">委托</param>
		public CRepeatRunner(IDelegate handler)
		{
			this._Delay = -1;
			this._ThreadState = -1;
			this._IsDisposed = false;
			this._Handler = handler;
			this._DelayWait = new ManualResetEvent(false);
		}

		/// <summary>
		/// 当前委托
		/// </summary>
		public IDelegate Handler
		{
			get
			{
				if (this._IsDisposed)
					throw new ObjectDisposedException(this.GetType().Name);

				return this._Handler;
			}
			set
			{
				if (this._IsDisposed)
					throw new ObjectDisposedException(this.GetType().Name);

				if (value == null)
					return;

				this._Handler = value;
			}
		}

		/// <summary>
		/// 获取用于等待重复操作完成的 System.Threading.WaitHandle。
		/// </summary>
		public WaitHandle RepeatWaitHandle
		{
			get
			{
				if (this._IsDisposed)
					throw new ObjectDisposedException(this.GetType().Name);

				return this._DelayWait;
			}
		}

		/// <summary>
		/// 开始
		/// </summary>
		/// <returns>是否成功</returns>
		public bool Start()
		{
			if (this._IsDisposed)
				return false;//throw new ObjectDisposedException(this.GetType().Name);

			if (this._Handler == null)
				return false;//throw

			if (this._ThreadState == (int)ThreadState.Running)
				return false;

			if (this._Thread == null)
			{
				this._Thread = new Thread(new ThreadStart(this.Run));
				this._Thread.IsBackground = true;
				if (!Monitor.TryEnter(CRepeatRunner._RepeatRunnerDictionary, Fiber.LockTimeout))
					Fiber.ThrowLockTimeoutException(CRepeatRunner._RepeatRunnerDictionary);
				try
				{
					CRepeatRunner._RepeatRunnerDictionary.Add(this._Thread, this);
				}
				finally
				{
					Monitor.Exit(CRepeatRunner._RepeatRunnerDictionary);
				}
				this._Thread.Start();
			}
			Interlocked.Exchange(ref this._ThreadState, (int)ThreadState.Running);
			return this._DelayWait.Set();
		}

		/// <summary>
		/// 暂停
		/// </summary>
		/// <returns>是否成功</returns>
		public bool Pause()
		{
			if (this._IsDisposed)
				return false;//throw new ObjectDisposedException(this.GetType().Name);

			if (this._Handler == null)
				return false;//throw

			if (this._ThreadState == (int)ThreadState.Suspended)
				return false;

			if (this._Thread == null)
				return false;

			Interlocked.Exchange(ref this._ThreadState, (int)ThreadState.Suspended);
			return this._DelayWait.Reset();
		}

		/// <summary>
		/// 停止
		/// </summary>
		/// <returns>是否成功</returns>
		public bool Stop()
		{
			if (this._IsDisposed)
				return false;//throw new ObjectDisposedException(this.GetType().Name);

			if (this._Handler == null)
				return false;//throw

			if (this._ThreadState == (int)ThreadState.Stopped)
				return false;

			if (this._Thread == null)
				return false;

			Interlocked.Exchange(ref this._ThreadState, (int)ThreadState.Stopped);
			return this._DelayWait.Set();
		}

		/// <summary>
		/// 取消此次执行，将引发 CRunnerCancelException 异常
		/// </summary>
		/// <returns>引发的异常</returns>
		public ThreadAbortException Cancel()
		{
			throw new RunnerCancelException();
		}

		/// <summary>
		/// 线程错误
		/// </summary>
		/// <param name="e">错误参数</param>
		protected void OnError(CErrorEventArgs e)
		{
			if (this.Error != null)
			{
				this.Error(this, e);
				return;
			}

			e.ThrowError = false;
		}

		/// <summary>
		/// 是否已开始
		/// </summary>
		public bool IsStarted
		{
			get
			{
				if (this._ThreadState == (int)ThreadState.Running)
					return true;

				return false;
			}
		}

		/// <summary>
		/// 是否已暂停
		/// </summary>
		public bool IsPaused
		{
			get
			{
				if (this._ThreadState == (int)ThreadState.Suspended)
					return true;

				return false;
			}
		}

		/// <summary>
		/// 是否已停止
		/// </summary>
		public bool IsStopped
		{
			get
			{
				if (this._ThreadState == (int)ThreadState.Stopped)
					return true;

				return false;
			}
		}

		/// <summary>
		/// 设置或获取延时时间（毫秒）
		/// </summary>
		public int Delay
		{
			set
			{
				Interlocked.Exchange(ref this._Delay, value);
			}
			get
			{
				return this._Delay;
			}
		}

		/// <summary>
		/// 已运行次数
		/// </summary>
		public int RanTimes
		{
			get
			{
				return this._RanTimes;
			}
		}

		/// <summary>
		/// 已出错次数
		/// </summary>
		public int ErrorTimes
		{
			get
			{
				return this._ErrorTimes;
			}
		}

		/// <summary>
		/// 设置或获取存储的附加数据
		/// </summary>
		public object Tag
		{
			set
			{
				this._Tag = value;
			}
			get
			{
				return this._Tag;
			}
		}

		/// <summary>
		/// 是否已请求停止，如果未停止，则等待暂停信号
		/// </summary>
		/// <returns></returns>
		public bool IsStopedAndWaitPause()
		{
			if (this._ThreadState == (int)ThreadState.Stopped)
				return true;

			if (this._ThreadState == (int)ThreadState.Suspended)
				this._DelayWait.WaitOne();
			return false;
		}

		/// <summary>
		/// 运行
		/// </summary>
		private void Run()
		{
			while (this._ThreadState != (int)ThreadState.Stopped)
			{
				if (this._IsDisposed)
					break;

				if (this._Handler == null)
				{
					this._DelayWait.Reset();
					this._DelayWait.WaitOne();
					continue;
				}

				this._DelayWait.Reset();
				if (this._Delay > 0)
					this._DelayWait.WaitOne(this._Delay);
				if (this._ThreadState == (int)ThreadState.Suspended)
					this._DelayWait.WaitOne();
				if (this._IsDisposed || this._ThreadState == (int)ThreadState.Stopped)
					break;

				while (true)
				{
					this._DelayWait.Set();
					try
					{
						this._Handler.Invoke();
						this._RanTimes++;
					}
					catch (RunnerCancelException x)
					{
						//continue;
					}
					catch (Exception x)
					{
						Tracker.WriteError(x);
						this._ErrorTimes++;
						CErrorEventArgs e = new CErrorEventArgs(this._Handler.Handler.Method);
						e.Error = x;
						this.OnError(e);
					}
					this._DelayWait.Reset();
					break;
				}
			}

			Interlocked.Exchange(ref this._ThreadState, (int)ThreadState.Stopped);
			if (!Monitor.TryEnter(CRepeatRunner._RepeatRunnerDictionary, Fiber.LockTimeout))
				Fiber.ThrowLockTimeoutException(CRepeatRunner._RepeatRunnerDictionary);
				try
				{
					CRepeatRunner._RepeatRunnerDictionary.Remove(this._Thread);
				}
				finally
				{
					Monitor.Exit(CRepeatRunner._RepeatRunnerDictionary);
				}
			this._Thread = null;

			if (!this._IsDisposed)
				return;

			this._DelayWait.Close();
			this._DelayWait = null;
			this._Handler.Dispose();
			this._Handler = null;
		}

		#region IDisposable 成员

		/// <summary>
		/// 释放所有资源
		/// </summary>
		public void Dispose()
		{
			//throw new NotImplementedException();
			this._IsDisposed = true;
			this.Stop();
		}

		/// <summary>
		/// 释放所有资源
		/// </summary>
		~CRepeatRunner()
		{
			this.Dispose();
		}

		#endregion

		/// <summary>
		/// 按当前的线程取对象
		/// </summary>
		/// <returns>对象</returns>
		public static CRepeatRunner GetRunner()
		{
			return CRepeatRunner.GetRunner(Thread.CurrentThread);
		}
		/// <summary>
		/// 按运行的线程取对象
		/// </summary>
		/// <param name="thread">运行线程</param>
		/// <returns>对象</returns>
		public static CRepeatRunner GetRunner(Thread thread)
		{
			if (!Monitor.TryEnter(CRepeatRunner._RepeatRunnerDictionary, Fiber.LockTimeout))
				Fiber.ThrowLockTimeoutException(CRepeatRunner._RepeatRunnerDictionary);
			try
			{
				if (!CRepeatRunner._RepeatRunnerDictionary.ContainsKey(thread))
					return null;

				return CRepeatRunner._RepeatRunnerDictionary[thread];
			}
			finally
			{
				Monitor.Exit(CRepeatRunner._RepeatRunnerDictionary);
			}
		}

		/// <summary>
		/// 开始所有
		/// </summary>
		/// <returns>成功数</returns>
		public static int StartAll()
		{
			if (!Monitor.TryEnter(CRepeatRunner._RepeatRunnerDictionary, Fiber.LockTimeout))
				Fiber.ThrowLockTimeoutException(CRepeatRunner._RepeatRunnerDictionary);
			try
			{
				var i = 0;
				foreach (var r in CRepeatRunner._RepeatRunnerDictionary.Values)
				{
					if (r.Start())
						i++;
				}
				return i;
			}
			finally
			{
				Monitor.Exit(CRepeatRunner._RepeatRunnerDictionary);
			}
		}

		/// <summary>
		/// 暂停所有
		/// </summary>
		/// <returns>成功数</returns>
		public static int PauseAll()
		{
			var i = 0;
			if (!Monitor.TryEnter(CRepeatRunner._RepeatRunnerDictionary, Fiber.LockTimeout))
				Fiber.ThrowLockTimeoutException(CRepeatRunner._RepeatRunnerDictionary);
			try
			{
				foreach (var r in CRepeatRunner._RepeatRunnerDictionary.Values)
				{
					if (r.Pause())
						i++;
				}
			}
			finally
			{
				Monitor.Exit(CRepeatRunner._RepeatRunnerDictionary);
			}
			return i;
		}

		/// <summary>
		/// 停止所有
		/// </summary>
		/// <returns>成功数</returns>
		public static int StopAll()
		{
			var i = 0;
			if (!Monitor.TryEnter(CRepeatRunner._RepeatRunnerDictionary, Fiber.LockTimeout))
				Fiber.ThrowLockTimeoutException(CRepeatRunner._RepeatRunnerDictionary);
			try
			{
				foreach (var r in CRepeatRunner._RepeatRunnerDictionary.Values)
				{
					if (r.Stop())
						i++;
				}
			}
			finally
			{
				Monitor.Exit(CRepeatRunner._RepeatRunnerDictionary);
			}
			return i;
		}

		/// <summary>
		/// Delegate EndInvoke AsyncCallback
		/// </summary>
		public static AsyncCallback InvokeAsyncCallback
		{
			get
			{
				if (CRepeatRunner._InvokeAsyncCallback == null)
					CRepeatRunner._InvokeAsyncCallback = new AsyncCallback(CRepeatRunner.EndInvoke);
				return CRepeatRunner._InvokeAsyncCallback;
			}
		}

		private static void EndInvoke(IAsyncResult result)
		{
			if (Thread.CurrentThread.IsThreadPoolThread && Fiber.QueueUserAsyncCallback(EndInvoke, result))
				return;

			if (result.AsyncState == null)
				return;

			var ms = result.AsyncState.GetType().GetMethods();
			if (ms == null || ms.Length == 0)
				return;

			int i;
			ParameterInfo[] ps;
			for (i = 0; i < ms.Length; i++)
			{
				ps = ms[i].GetParameters();
				if (ps == null || ps.Length != 1)
					continue;

				if (ps[0].ParameterType == result.GetType())
					break;

				if (ps[0].ParameterType.IsInstanceOfType(result))
					break;

				if (ps[0].ParameterType.IsSubclassOf(result.GetType()))
					break;
			}

			if (i >= ms.Length)
				return;

			ms[i].Invoke(result, new object[] { result });
		}

		/// <summary>
		/// 将当前线程挂起指定的时间。
		/// </summary>
		/// <param name="millisecondsTimeout">线程被阻塞的毫秒数。指定零 (0) 以指示应挂起此线程以使其他等待线程能够执行。指定 System.Threading.Timeout.Infinite 以无限期阻止线程。</param>
		/// <exception cref="System.ArgumentOutOfRangeException">超时值为负且不等于 System.Threading.Timeout.Infinite。</exception>
		/// <returns>当前线程</returns>
		public static Thread Sleep(int millisecondsTimeout)
		{
			Thread.Sleep(millisecondsTimeout);
			return Thread.CurrentThread;
		}
		/// <summary>
		/// 将当前线程阻塞指定的时间。
		/// </summary>
		/// <param name="timeout">设置为线程被阻塞的时间量的 System.TimeSpan。指定零以指示应挂起此线程以使其他等待线程能够执行。指定 System.Threading.Timeout.Infinite 以无限期阻止线程。</param>
		/// <exception cref="System.ArgumentOutOfRangeException">timeout 的值为负，而且不等于 System.Threading.Timeout.Infinite（以毫秒为单位），或者大于 System.Int32.MaxValue 毫秒。</exception>
		/// <returns>当前线程</returns>
		public static Thread Sleep(TimeSpan timeout)
		{
			Thread.Sleep(timeout);
			return Thread.CurrentThread;
		}
	}
}
